/*-------------------------------------------------------------------------
 *
 * rewriteManip.c
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/rewrite/rewriteManip.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/pathnodes.h"
#include "nodes/plannodes.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
#include "utils/lsyscache.h"


typedef struct
{
	int			sublevels_up;
} contain_aggs_of_level_context;

typedef struct
{
	int			agg_location;
	int			sublevels_up;
} locate_agg_of_level_context;

typedef struct
{
	int			win_location;
} locate_windowfunc_context;

static bool fc_contain_aggs_of_level_walker(Node *fc_node,
										 contain_aggs_of_level_context *fc_context);
static bool fc_locate_agg_of_level_walker(Node *fc_node,
									   locate_agg_of_level_context *fc_context);
static bool fc_contain_windowfuncs_walker(Node *fc_node, void *fc_context);
static bool fc_locate_windowfunc_walker(Node *fc_node,
									 locate_windowfunc_context *fc_context);
static bool fc_checkExprHasSubLink_walker(Node *fc_node, void *fc_context);
static Relids fc_offset_relid_set(Relids fc_relids, int fc_offset);
static Relids fc_adjust_relid_set(Relids fc_relids, int fc_oldrelid, int fc_newrelid);


/*
 * contain_aggs_of_level -
 *   检查表达式是否包含指定查询级别的聚合函数调用。
 *
 * 该例程的目的是检测是否存在属于给定查询级别的聚合。
 * 属于子查询或外部查询的聚合不会导致真正的结果。
 * 我们必须递归进入子查询以检测逻辑上属于指定查询级别的外部引用聚合。
 */
bool contain_aggs_of_level(Node *fc_node, int fc_levelsup)
{
	contain_aggs_of_level_context fc_context;

	fc_context.sublevels_up = fc_levelsup;

	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	return query_or_expression_tree_walker(fc_node,
										   fc_contain_aggs_of_level_walker,
										   (void *) &fc_context,
										   0);
}

static bool fc_contain_aggs_of_level_walker(Node *fc_node,
							 contain_aggs_of_level_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Aggref))
	{
		if (((Aggref *) fc_node)->agglevelsup == fc_context->sublevels_up)
			return true;		/* 中止树遍历并返回 true */
		/* 否则继续检查参数 */
	}
	if (IsA(fc_node, GroupingFunc))
	{
		if (((GroupingFunc *) fc_node)->agglevelsup == fc_context->sublevels_up)
			return true;
		/* 否则继续检查参数 */
	}
	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node,
								   fc_contain_aggs_of_level_walker,
								   (void *) fc_context, 0);
		fc_context->sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_contain_aggs_of_level_walker,
								  (void *) fc_context);
}

/*
 * locate_agg_of_level -
 *	  查找指定查询级别的任何聚合的解析位置。
 *
 * 如果查询树中没有这样的聚合，或者它们都有未知的解析位置，则返回 -1。
 * （前一种情况可能是调用者错误，但我们不忙于将其与后一种情况区分开。）
 *
 * 注意：将此功能合并到 contain_aggs_of_level 中似乎是适当的，但这会使该函数的 API 复杂化。
 * 当前，该函数的唯一用途是错误报告，因此节省周期可能并不是非常重要。
 */
int locate_agg_of_level(Node *fc_node, int fc_levelsup)
{
	locate_agg_of_level_context fc_context;

	fc_context.agg_location = -1;	/* 如果我们什么都没找到 */
	fc_context.sublevels_up = fc_levelsup;

	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	(void) query_or_expression_tree_walker(fc_node,
										   fc_locate_agg_of_level_walker,
										   (void *) &fc_context,
										   0);

	return fc_context.agg_location;
}

static bool fc_locate_agg_of_level_walker(Node *fc_node,
						   locate_agg_of_level_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Aggref))
	{
		if (((Aggref *) fc_node)->agglevelsup == fc_context->sublevels_up &&
			((Aggref *) fc_node)->location >= 0)
		{
			fc_context->agg_location = ((Aggref *) fc_node)->location;
			return true;		/* 中止树遍历并返回 true */
		}
		/* 否则继续检查参数 */
	}
	if (IsA(fc_node, GroupingFunc))
	{
		if (((GroupingFunc *) fc_node)->agglevelsup == fc_context->sublevels_up &&
			((GroupingFunc *) fc_node)->location >= 0)
		{
			fc_context->agg_location = ((GroupingFunc *) fc_node)->location;
			return true;		/* 中止树遍历并返回 true */
		}
	}
	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node,
								   fc_locate_agg_of_level_walker,
								   (void *) fc_context, 0);
		fc_context->sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_locate_agg_of_level_walker,
								  (void *) fc_context);
}

/*
 * contain_windowfuncs -
 *	检查表达式是否包含当前查询级别的窗口函数调用。
 */
bool contain_windowfuncs(Node *fc_node)
{
	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	return query_or_expression_tree_walker(fc_node,
										   fc_contain_windowfuncs_walker,
										   NULL,
										   0);
}

static bool fc_contain_windowfuncs_walker(Node *fc_node, void *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, WindowFunc))
		return true;			/* 中止树遍历并返回 true */
	/* 不应该递归进入子查询 */
	return expression_tree_walker(fc_node, fc_contain_windowfuncs_walker,
								  (void *) fc_context);
}

/*
 * locate_windowfunc -
 *	  找到当前查询级别的任何窗口函数的解析位置。
 *
 * 如果查询树中没有这样的窗口函数，或者它们的解析位置未知，则返回 -1。
 * （前一种情况可能是调用者错误，但我们不去区分后一种情况。）
 *
 * 注意：将此功能合并到 contain_windowfuncs 似乎合适，但那会使该函数的 API 变复杂。
 * 目前，此函数的唯一用途是用于错误报告，因此节省时间可能不是很重要。
 */
int locate_windowfunc(Node *fc_node)
{
	locate_windowfunc_context fc_context;

	fc_context.win_location = -1;	/* 如果我们什么都没找到 */

	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	(void) query_or_expression_tree_walker(fc_node,
										   fc_locate_windowfunc_walker,
										   (void *) &fc_context,
										   0);

	return fc_context.win_location;
}

static bool fc_locate_windowfunc_walker(Node *fc_node, locate_windowfunc_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, WindowFunc))
	{
		if (((WindowFunc *) fc_node)->location >= 0)
		{
			fc_context->win_location = ((WindowFunc *) fc_node)->location;
			return true;		/* 中止树遍历并返回 true */
		}
		/* 否则继续检查参数 */
	}
	/* 不应该递归进入子查询 */
	return expression_tree_walker(fc_node, fc_locate_windowfunc_walker,
								  (void *) fc_context);
}

/*
 * checkExprHasSubLink -
 *	检查表达式是否包含 SubLink。
 */
bool checkExprHasSubLink(Node *fc_node)
{
	/*
	 * 如果传递的是查询，则检查它——但我们不应该递归进入其 rangetable 或 CTE 列表中的子查询。
	 */
	return query_or_expression_tree_walker(fc_node,
										   fc_checkExprHasSubLink_walker,
										   NULL,
										   QTW_IGNORE_RC_SUBQUERIES);
}

static bool fc_checkExprHasSubLink_walker(Node *fc_node, void *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, SubLink))
		return true;			/* 中止树遍历并返回 true */
	return expression_tree_walker(fc_node, fc_checkExprHasSubLink_walker, fc_context);
}

/*
 * 检查表达式树中的 MULTIEXPR 参数
 *
 * 我们故意不深入到 SubLinks：只有当前查询级别的 Params 才是关注的重点。
 */
static bool fc_contains_multiexpr_param(Node *fc_node, void *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Param))
	{
		if (((Param *) fc_node)->paramkind == PARAM_MULTIEXPR)
			return true;		/* 中止树遍历并返回 true */
		return false;
	}
	return expression_tree_walker(fc_node, fc_contains_multiexpr_param, fc_context);
}


/*
 * OffsetVarNodes - 在将一个查询的 RT 附加到另一个时调整 Var
 *
 * 查找给定树中所有 varlevelsup == sublevels_up 的 Var 节点，
 * 并将它们的 varno 字段（rangetable 索引）加上 'offset'。
 * varnosyn 字段也类似调整。此外，还要调整包含 rangetable 索引的其他节点，
 * 如 RangeTblRef 和 JoinExpr。
 *
 * 注意：尽管这具有 walker 的形式，我们会作弊并就地修改节点。
 * 给定的表达式树应该在此之前被复制，以确保不会发生不必要的副作用！
 */

typedef struct
{
	int			offset;
	int			sublevels_up;
} OffsetVarNodes_context;

static bool fc_OffsetVarNodes_walker(Node *fc_node, OffsetVarNodes_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Var))
	{
		Var		   *fc_var = (Var *) fc_node;

		if (fc_var->varlevelsup == fc_context->sublevels_up)
		{
			fc_var->varno += fc_context->offset;
			if (fc_var->varnosyn > 0)
				fc_var->varnosyn += fc_context->offset;
		}
		return false;
	}
	if (IsA(fc_node, CurrentOfExpr))
	{
		CurrentOfExpr *fc_cexpr = (CurrentOfExpr *) fc_node;

		if (fc_context->sublevels_up == 0)
			fc_cexpr->cvarno += fc_context->offset;
		return false;
	}
	if (IsA(fc_node, RangeTblRef))
	{
		RangeTblRef *fc_rtr = (RangeTblRef *) fc_node;

		if (fc_context->sublevels_up == 0)
			fc_rtr->rtindex += fc_context->offset;
		/* 子查询本身将单独访问 */
		return false;
	}
	if (IsA(fc_node, JoinExpr))
	{
		JoinExpr   *fc_j = (JoinExpr *) fc_node;

		if (fc_j->rtindex && fc_context->sublevels_up == 0)
			fc_j->rtindex += fc_context->offset;
		/* 继续检查子节点 */
	}
	if (IsA(fc_node, PlaceHolderVar))
	{
		PlaceHolderVar *fc_phv = (PlaceHolderVar *) fc_node;

		if (fc_phv->phlevelsup == fc_context->sublevels_up)
		{
			fc_phv->phrels = fc_offset_relid_set(fc_phv->phrels,
										   fc_context->offset);
		}
		/* 继续检查子节点 */
	}
	if (IsA(fc_node, AppendRelInfo))
	{
		AppendRelInfo *fc_appinfo = (AppendRelInfo *) fc_node;

		if (fc_context->sublevels_up == 0)
		{
			fc_appinfo->parent_relid += fc_context->offset;
			fc_appinfo->child_relid += fc_context->offset;
		}
		/* 继续检查子节点 */
	}
	/* 不需要在这里处理其他规划辅助节点 */
	Assert(!IsA(fc_node, PlanRowMark));
	Assert(!IsA(fc_node, SpecialJoinInfo));
	Assert(!IsA(fc_node, PlaceHolderInfo));
	Assert(!IsA(fc_node, MinMaxAggInfo));

	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node, fc_OffsetVarNodes_walker,
								   (void *) fc_context, 0);
		fc_context->sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_OffsetVarNodes_walker,
								  (void *) fc_context);
}

void OffsetVarNodes(Node *fc_node, int fc_offset, int fc_sublevels_up)
{
	OffsetVarNodes_context fc_context;

	fc_context.offset = fc_offset;
	fc_context.sublevels_up = fc_sublevels_up;

	/*
	 * 必须准备好以查询或裸表达式树开始；如果它是一个查询，
	 * 请直接转到 query_tree_walker，以确保 sublevels_up 不会提前递增。
	 */
	if (fc_node && IsA(fc_node, Query))
	{
		Query	   *fc_qry = (Query *) fc_node;

		/*
		 * 如果我们从 Query 开始，并且 sublevels_up 为零，
		 * 那么我们还必须修复 Query 本身中的 rangetable 索引——也就是说
		 * resultRelation、exclRelIndex 和 rowMarks 条目。递归进入子查询时
		 * sublevels_up 不能为零，因此在 OffsetVarNodes_walker 中没有必要
		 * 使用相同的逻辑。
		 */
		if (fc_sublevels_up == 0)
		{
			ListCell   *fc_l;

			if (fc_qry->resultRelation)
				fc_qry->resultRelation += fc_offset;

			if (fc_qry->onConflict && fc_qry->onConflict->exclRelIndex)
				fc_qry->onConflict->exclRelIndex += fc_offset;

			foreach(fc_l, fc_qry->rowMarks)
			{
				RowMarkClause *fc_rc = (RowMarkClause *) lfirst(fc_l);

				fc_rc->rti += fc_offset;
			}
		}
		query_tree_walker(fc_qry, fc_OffsetVarNodes_walker,
						  (void *) &fc_context, 0);
	}
	else
		fc_OffsetVarNodes_walker(fc_node, &fc_context);
}

static Relids fc_offset_relid_set(Relids fc_relids, int fc_offset)
{
	Relids		fc_result = NULL;
	int			fc_rtindex;

	fc_rtindex = -1;
	while ((fc_rtindex = bms_next_member(fc_relids, fc_rtindex)) >= 0)
		fc_result = bms_add_member(fc_result, fc_rtindex + fc_offset);
	return fc_result;
}

/*
 * ChangeVarNodes - 针对特定的 RT 索引变化调整 Var 节点
 *
 * 查找给定树中属于特定关系的所有 Var 节点
 * （通过 sublevels_up 和 rt_index 确定），并将它们的 varno 字段
 * 更改为 'new_index'。varnosyn 字段也被更改。此外，还要调整其他
 * 包含 rangetable 索引的节点，如 RangeTblRef 和 JoinExpr。
 *
 * 注意：尽管这具有 walker 的形式，我们会作弊并就地修改节点。
 * 给定的表达式树应该在此之前被复制，以确保不会发生不必要的副作用！
 */

typedef struct
{
	int			rt_index;
	int			new_index;
	int			sublevels_up;
} ChangeVarNodes_context;

static bool fc_ChangeVarNodes_walker(Node *fc_node, ChangeVarNodes_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Var))
	{
		Var		   *fc_var = (Var *) fc_node;

		if (fc_var->varlevelsup == fc_context->sublevels_up &&
			fc_var->varno == fc_context->rt_index)
		{
			fc_var->varno = fc_context->new_index;
			/* 如果语法参照相同的 RTE，也修复它 */
			if (fc_var->varnosyn == fc_context->rt_index)
				fc_var->varnosyn = fc_context->new_index;
		}
		return false;
	}
	if (IsA(fc_node, CurrentOfExpr))
	{
		CurrentOfExpr *fc_cexpr = (CurrentOfExpr *) fc_node;

		if (fc_context->sublevels_up == 0 &&
			fc_cexpr->cvarno == fc_context->rt_index)
			fc_cexpr->cvarno = fc_context->new_index;
		return false;
	}
	if (IsA(fc_node, RangeTblRef))
	{
		RangeTblRef *fc_rtr = (RangeTblRef *) fc_node;

		if (fc_context->sublevels_up == 0 &&
			fc_rtr->rtindex == fc_context->rt_index)
			fc_rtr->rtindex = fc_context->new_index;
		/* 子查询本身将单独访问 */
		return false;
	}
	if (IsA(fc_node, JoinExpr))
	{
		JoinExpr   *fc_j = (JoinExpr *) fc_node;

		if (fc_context->sublevels_up == 0 &&
			fc_j->rtindex == fc_context->rt_index)
			fc_j->rtindex = fc_context->new_index;
		/* 继续检查子节点 */
	}
	if (IsA(fc_node, PlaceHolderVar))
	{
		PlaceHolderVar *fc_phv = (PlaceHolderVar *) fc_node;

		if (fc_phv->phlevelsup == fc_context->sublevels_up)
		{
			fc_phv->phrels = fc_adjust_relid_set(fc_phv->phrels,
										   fc_context->rt_index,
										   fc_context->new_index);
		}
		/* 继续检查子节点 */
	}
	if (IsA(fc_node, PlanRowMark))
	{
		PlanRowMark *fc_rowmark = (PlanRowMark *) fc_node;

		if (fc_context->sublevels_up == 0)
		{
			if (fc_rowmark->rti == fc_context->rt_index)
				fc_rowmark->rti = fc_context->new_index;
			if (fc_rowmark->prti == fc_context->rt_index)
				fc_rowmark->prti = fc_context->new_index;
		}
		return false;
	}
	if (IsA(fc_node, AppendRelInfo))
	{
		AppendRelInfo *fc_appinfo = (AppendRelInfo *) fc_node;

		if (fc_context->sublevels_up == 0)
		{
			if (fc_appinfo->parent_relid == fc_context->rt_index)
				fc_appinfo->parent_relid = fc_context->new_index;
			if (fc_appinfo->child_relid == fc_context->rt_index)
				fc_appinfo->child_relid = fc_context->new_index;
		}
		/* 继续检查子节点 */
	}
	/* 不需要在这里处理其他规划辅助节点 */
	Assert(!IsA(fc_node, SpecialJoinInfo));
	Assert(!IsA(fc_node, PlaceHolderInfo));
	Assert(!IsA(fc_node, MinMaxAggInfo));

	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node, fc_ChangeVarNodes_walker,
								   (void *) fc_context, 0);
		fc_context->sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_ChangeVarNodes_walker,
								  (void *) fc_context);
}

void ChangeVarNodes(Node *fc_node, int fc_rt_index, int fc_new_index, int fc_sublevels_up)
{
	ChangeVarNodes_context fc_context;

	fc_context.rt_index = fc_rt_index;
	fc_context.new_index = fc_new_index;
	fc_context.sublevels_up = fc_sublevels_up;

	/*
	 * 必须准备好以查询或裸表达式树开始；如果它是一个查询，
	 * 请直接转到 query_tree_walker，以确保 sublevels_up 不会提前递增。
	 */
	if (fc_node && IsA(fc_node, Query))
	{
		Query	   *fc_qry = (Query *) fc_node;

		/*
		 * 如果我们从 Query 开始，并且 sublevels_up 为零，
		 * 那么我们还必须修复 Query 本身中的 rangetable 索引——即
		 * resultRelation 和 rowMarks 条目。递归进入子查询时
		 * sublevels_up 不能为零，所以在 ChangeVarNodes_walker 中
		 * 没有必要使用相同的逻辑。
		 */
		if (fc_sublevels_up == 0)
		{
			ListCell   *fc_l;

			if (fc_qry->resultRelation == fc_rt_index)
				fc_qry->resultRelation = fc_new_index;

			/* 这不太可能被使用，但... */
			if (fc_qry->onConflict && fc_qry->onConflict->exclRelIndex == fc_rt_index)
				fc_qry->onConflict->exclRelIndex = fc_new_index;

			foreach(fc_l, fc_qry->rowMarks)
			{
				RowMarkClause *fc_rc = (RowMarkClause *) lfirst(fc_l);

				if (fc_rc->rti == fc_rt_index)
					fc_rc->rti = fc_new_index;
			}
		}
		query_tree_walker(fc_qry, fc_ChangeVarNodes_walker,
						  (void *) &fc_context, 0);
	}
	else
		fc_ChangeVarNodes_walker(fc_node, &fc_context);
}

/*
 * 在 Relid 集中为 oldrelid 替换 newrelid
 */
static Relids fc_adjust_relid_set(Relids fc_relids, int fc_oldrelid, int fc_newrelid)
{
	if (bms_is_member(fc_oldrelid, fc_relids))
	{
		/* 确保我们有一个可修改的副本 */
		fc_relids = bms_copy(fc_relids);
		/* 删除旧的，添加新的 */
		fc_relids = bms_del_member(fc_relids, fc_oldrelid);
		fc_relids = bms_add_member(fc_relids, fc_newrelid);
	}
	return fc_relids;
}

/*
 * IncrementVarSublevelsUp - 在树中向下推送 Var 节点时调整
 *
 * 查找给定树中所有 varlevelsup >= min_sublevels_up 的 Var 节点，
 * 并将 delta_sublevels_up 添加到它们的 varlevelsup 值中。
 * 当将某个适用于某一嵌套级别的表达式插入子查询时，这很有必要。
 * 通常，初始调用的 min_sublevels_up == 0，以便影响所有 Var。
 * min_sublevels_up 的要点在于，我们可以在递归进入 SubLink 时增加它，
 * 以便子链接中的局部变量不受影响，只有属于表达式原查询级别或其父级的外部变量引用受到影响。
 *
 * 对于包含 levelsup 字段的其他节点也是如此，比如 Aggref。
 *
 * 注意：尽管这具有 walker 的形式，我们会作弊并就地修改 Var 节点。
 * 给定的表达式树应该在此之前被复制，以确保不会发生不必要的副作用！
 */

typedef struct
{
	int			delta_sublevels_up;
	int			min_sublevels_up;
} IncrementVarSublevelsUp_context;

static bool fc_IncrementVarSublevelsUp_walker(Node *fc_node,
							   IncrementVarSublevelsUp_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Var))
	{
		Var		   *fc_var = (Var *) fc_node;

		if (fc_var->varlevelsup >= fc_context->min_sublevels_up)
			fc_var->varlevelsup += fc_context->delta_sublevels_up;
		return false;			/* 完成这里 */
	}
	if (IsA(fc_node, CurrentOfExpr))
	{
		/* 这不应该发生 */
		if (fc_context->min_sublevels_up == 0)
			elog(ERROR, "cannot push down CurrentOfExpr");
		return false;
	}
	if (IsA(fc_node, Aggref))
	{
		Aggref	   *fc_agg = (Aggref *) fc_node;

		if (fc_agg->agglevelsup >= fc_context->min_sublevels_up)
			fc_agg->agglevelsup += fc_context->delta_sublevels_up;
		/* 跳过以递归进入参数 */
	}
	if (IsA(fc_node, GroupingFunc))
	{
		GroupingFunc *fc_grp = (GroupingFunc *) fc_node;

		if (fc_grp->agglevelsup >= fc_context->min_sublevels_up)
			fc_grp->agglevelsup += fc_context->delta_sublevels_up;
		/* 跳过以递归进入参数 */
	}
	if (IsA(fc_node, PlaceHolderVar))
	{
		PlaceHolderVar *fc_phv = (PlaceHolderVar *) fc_node;

		if (fc_phv->phlevelsup >= fc_context->min_sublevels_up)
			fc_phv->phlevelsup += fc_context->delta_sublevels_up;
		/* 跳过以递归进入参数 */
	}
	if (IsA(fc_node, RangeTblEntry))
	{
		RangeTblEntry *fc_rte = (RangeTblEntry *) fc_node;

		if (fc_rte->rtekind == RTE_CTE)
		{
			if (fc_rte->ctelevelsup >= fc_context->min_sublevels_up)
				fc_rte->ctelevelsup += fc_context->delta_sublevels_up;
		}
		return false;			/* 允许 range_table_walker 继续 */
	}
	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->min_sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node,
								   fc_IncrementVarSublevelsUp_walker,
								   (void *) fc_context,
								   QTW_EXAMINE_RTES_BEFORE);
		fc_context->min_sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_IncrementVarSublevelsUp_walker,
								  (void *) fc_context);
}

void IncrementVarSublevelsUp(Node *fc_node, int fc_delta_sublevels_up,
						int fc_min_sublevels_up)
{
	IncrementVarSublevelsUp_context fc_context;

	fc_context.delta_sublevels_up = fc_delta_sublevels_up;
	fc_context.min_sublevels_up = fc_min_sublevels_up;

	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	query_or_expression_tree_walker(fc_node,
									fc_IncrementVarSublevelsUp_walker,
									(void *) &fc_context,
									QTW_EXAMINE_RTES_BEFORE);
}

/*
 * IncrementVarSublevelsUp_rtable -
 *	与 IncrementVarSublevelsUp 相同，但在范围表上调用。
 */
void IncrementVarSublevelsUp_rtable(List *fc_rtable, int fc_delta_sublevels_up,
							   int fc_min_sublevels_up)
{
	IncrementVarSublevelsUp_context fc_context;

	fc_context.delta_sublevels_up = fc_delta_sublevels_up;
	fc_context.min_sublevels_up = fc_min_sublevels_up;

	range_table_walker(fc_rtable,
					   fc_IncrementVarSublevelsUp_walker,
					   (void *) &fc_context,
					   QTW_EXAMINE_RTES_BEFORE);
}



/*
 * rangeTableEntry_used - 检测某个 RTE 是否在查询或表达式的 var 节点或 join 或 setOp 树中被引用。
 */

typedef struct
{
	int			rt_index;
	int			sublevels_up;
} rangeTableEntry_used_context;

static bool fc_rangeTableEntry_used_walker(Node *fc_node,
							rangeTableEntry_used_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Var))
	{
		Var		   *fc_var = (Var *) fc_node;

		if (fc_var->varlevelsup == fc_context->sublevels_up &&
			fc_var->varno == fc_context->rt_index)
			return true;
		return false;
	}
	if (IsA(fc_node, CurrentOfExpr))
	{
		CurrentOfExpr *fc_cexpr = (CurrentOfExpr *) fc_node;

		if (fc_context->sublevels_up == 0 &&
			fc_cexpr->cvarno == fc_context->rt_index)
			return true;
		return false;
	}
	if (IsA(fc_node, RangeTblRef))
	{
		RangeTblRef *fc_rtr = (RangeTblRef *) fc_node;

		if (fc_rtr->rtindex == fc_context->rt_index &&
			fc_context->sublevels_up == 0)
			return true;
		/* 子查询本身将单独访问 */
		return false;
	}
	if (IsA(fc_node, JoinExpr))
	{
		JoinExpr   *fc_j = (JoinExpr *) fc_node;

		if (fc_j->rtindex == fc_context->rt_index &&
			fc_context->sublevels_up == 0)
			return true;
		/* 继续检查子节点 */
	}
	/* 这里不需要处理规划辅助节点 */
	Assert(!IsA(fc_node, PlaceHolderVar));
	Assert(!IsA(fc_node, PlanRowMark));
	Assert(!IsA(fc_node, SpecialJoinInfo));
	Assert(!IsA(fc_node, AppendRelInfo));
	Assert(!IsA(fc_node, PlaceHolderInfo));
	Assert(!IsA(fc_node, MinMaxAggInfo));

	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node, fc_rangeTableEntry_used_walker,
								   (void *) fc_context, 0);
		fc_context->sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_rangeTableEntry_used_walker,
								  (void *) fc_context);
}

bool rangeTableEntry_used(Node *fc_node, int fc_rt_index, int fc_sublevels_up)
{
	rangeTableEntry_used_context fc_context;

	fc_context.rt_index = fc_rt_index;
	fc_context.sublevels_up = fc_sublevels_up;

	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	return query_or_expression_tree_walker(fc_node,
										   fc_rangeTableEntry_used_walker,
										   (void *) &fc_context,
										   0);
}


/*
 * 如果给定的查询是一个 INSERT ... SELECT 结构，提取并
 * 返回表示 SELECT 部分的子查询节点。否则，
 * 返回给定的查询。
 *
 * 如果 subquery_ptr 不是 NULL，则 *subquery_ptr 被设置为
 * parsetree 中指向 SELECT 子查询的链接位置，如果不是
 * INSERT ... SELECT，则为 NULL。
 *
 * 这是一个必要的黑客，这是因为在规则操作中出现的
 * INSERT ... SELECT 的转换应该应用于源 SELECT，而不是
 * INSERT 部分。也许这可以通过重新设计的查询树来清理。
 */
Query * getInsertSelectQuery(Query *fc_parsetree, Query ***fc_subquery_ptr)
{
	Query	   *fc_selectquery;
	RangeTblEntry *fc_selectrte;
	RangeTblRef *fc_rtr;

	if (fc_subquery_ptr)
		*fc_subquery_ptr = NULL;

	if (fc_parsetree == NULL)
		return fc_parsetree;
	if (fc_parsetree->commandType != CMD_INSERT)
		return fc_parsetree;

	/*
	 * 目前，这仅应用于规则操作查询，因此我们
	 * 预计在给定的查询中找到 OLD 和 NEW 占位符条目。
	 * 如果它们不在，那么它一定是一个 INSERT/SELECT，
	 * 它们已经被推送到 SELECT 中。
	 */
	if (list_length(fc_parsetree->rtable) >= 2 &&
		strcmp(rt_fetch(PRS2_OLD_VARNO, fc_parsetree->rtable)->eref->aliasname,
			   "old") == 0 &&
		strcmp(rt_fetch(PRS2_NEW_VARNO, fc_parsetree->rtable)->eref->aliasname,
			   "new") == 0)
		return fc_parsetree;
	Assert(fc_parsetree->jointree && IsA(fc_parsetree->jointree, FromExpr));
	if (list_length(fc_parsetree->jointree->fromlist) != 1)
		elog(ERROR, "expected to find SELECT subquery");
	fc_rtr = (RangeTblRef *) linitial(fc_parsetree->jointree->fromlist);
	if (!IsA(fc_rtr, RangeTblRef))
		elog(ERROR, "expected to find SELECT subquery");
	fc_selectrte = rt_fetch(fc_rtr->rtindex, fc_parsetree->rtable);
	if (!(fc_selectrte->rtekind == RTE_SUBQUERY &&
		  fc_selectrte->subquery &&
		  IsA(fc_selectrte->subquery, Query) &&
		  fc_selectrte->subquery->commandType == CMD_SELECT))
		elog(ERROR, "expected to find SELECT subquery");
	fc_selectquery = fc_selectrte->subquery;
	if (list_length(fc_selectquery->rtable) >= 2 &&
		strcmp(rt_fetch(PRS2_OLD_VARNO, fc_selectquery->rtable)->eref->aliasname,
			   "old") == 0 &&
		strcmp(rt_fetch(PRS2_NEW_VARNO, fc_selectquery->rtable)->eref->aliasname,
			   "new") == 0)
	{
		if (fc_subquery_ptr)
			*fc_subquery_ptr = &(fc_selectrte->subquery);
		return fc_selectquery;
	}
	elog(ERROR, "could not find rule placeholders");
	return NULL;				/* 未到达 */
}


/*
 * 将给定的限定条件添加到查询的 WHERE 子句中
 */
void AddQual(Query *fc_parsetree, Node *fc_qual)
{
	Node	   *fc_copy;

	if (fc_qual == NULL)
		return;

	if (fc_parsetree->commandType == CMD_UTILITY)
	{
		/*
		 * 在一个实用语句中无处放置限定条件。
		 *
		 * 如果是 NOTIFY，则默默忽略限定条件；这意味着
		 * NOTIFY 将执行，无论是否有任何符合条件的行。
		 * 虽然显然是错误的，但这比完全拒绝
		 * 执行规则要有用得多，而且额外的 NOTIFY 事件对
		 * NOTIFY 的典型使用是无害的。
		 *
		 * 如果它不是 NOTIFY，则报错，因为无条件执行
		 * 其他实用语句不太可能是想要的。（这种情况目前
		 * 不被允许，但出于安全考虑保留该测试。）
		 */
		if (fc_parsetree->utilityStmt && IsA(fc_parsetree->utilityStmt, NotifyStmt))
			return;
		else
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("conditional utility statements are not implemented")));
	}

	if (fc_parsetree->setOperations != NULL)
	{
		/*
		 * 在一个 setop 语句中也无处放置限定条件。（这
		 * 可以修复，但目前计划程序会忽略任何 setop 查询上的
		 * 限定条件。）
		 */
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
	}

	/* INTERSECT 想要原始值，但我们需要复制 - Jan */
	fc_copy = copyObject(fc_qual);

	fc_parsetree->jointree->quals = make_and_qual(fc_parsetree->jointree->quals,
											   fc_copy);

	/*
	 * 我们最好不要将聚合函数放入 WHERE 语句中。
	 */
	Assert(!contain_aggs_of_level(fc_copy, 0));

	/*
	 * 如果添加的条件有子链接，确保查询被正确标记。查询已经标记时，无需搜索条件。
	 */
	if (!fc_parsetree->hasSubLinks)
		fc_parsetree->hasSubLinks = checkExprHasSubLink(fc_copy);
}


/*
 * 反转给定的子句并将其添加到给定的查询树的 WHERE 资格中。反转意味着“x 不为真”，而不仅仅是“非 x”，否则当 x 评估为 NULL 时，我们会做错误的事情。
 */
void AddInvertedQual(Query *fc_parsetree, Node *fc_qual)
{
	BooleanTest *fc_invqual;

	if (fc_qual == NULL)
		return;

	/* 无需复制输入条件，因为 AddQual 会... */
	fc_invqual = makeNode(BooleanTest);
	fc_invqual->arg = (Expr *) fc_qual;
	fc_invqual->booltesttype = IS_NOT_TRUE;
	fc_invqual->location = -1;

	AddQual(fc_parsetree, (Node *) fc_invqual);
}


/*
 * replace_rte_variables() 找到表达式树中引用特定 RTE 的所有 Var，并用从调用者提供的回调函数获得的替代表达式替换它们。
 *
 * 在对 Query 的一部分调用 replace_rte_variables 时，将包含 Query 的 hasSubLinks 字段的地址作为 outer_hasSubLinks 传递。否则，传递 NULL，但将 SubLink 插入非查询表达式将导致错误。
 *
 * 注意：插入的 sublink 相关的操作需要在替换添加子查询到子查询中的情况下更新 hasSubLinks。在这里有点混乱，不是吗？我们不需要为 hasAggs 做类似的操作，因为此转换不可能在子查询中插入一个水平零的聚合引用——它只能插入外部聚合。同样适用于 hasWindowFuncs。
 *
 * 注意：通常，我们不会公开这样的函数的变异器函数或上下文结构。我们这样做是因为回调通常发现直接递归到子表达式的变异器是方便的。
 */
Node * replace_rte_variables(Node *fc_node, int fc_target_varno, int fc_sublevels_up,
					  replace_rte_variables_callback fc_callback,
					  void *fc_callback_arg,
					  bool *fc_outer_hasSubLinks)
{
	Node	   *fc_result;
	replace_rte_variables_context fc_context;

	fc_context.callback = fc_callback;
	fc_context.callback_arg = fc_callback_arg;
	fc_context.target_varno = fc_target_varno;
	fc_context.sublevels_up = fc_sublevels_up;

	/*
	 * 如果查询已经有一些子链接，我们尝试将 inserted_sublink 初始化为 true，以便无需检测新的子链接。
	 */
	if (fc_node && IsA(fc_node, Query))
		fc_context.inserted_sublink = ((Query *) fc_node)->hasSubLinks;
	else if (fc_outer_hasSubLinks)
		fc_context.inserted_sublink = *fc_outer_hasSubLinks;
	else
		fc_context.inserted_sublink = false;

	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	fc_result = query_or_expression_tree_mutator(fc_node,
											  replace_rte_variables_mutator,
											  (void *) &fc_context,
											  0);

	if (fc_context.inserted_sublink)
	{
		if (fc_result && IsA(fc_result, Query))
			((Query *) fc_result)->hasSubLinks = true;
		else if (fc_outer_hasSubLinks)
			*fc_outer_hasSubLinks = true;
		else
			elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
	}

	return fc_result;
}

Node * replace_rte_variables_mutator(Node *fc_node,
							  replace_rte_variables_context *fc_context)
{
	if (fc_node == NULL)
		return NULL;
	if (IsA(fc_node, Var))
	{
		Var		   *fc_var = (Var *) fc_node;

		if (fc_var->varno == fc_context->target_varno &&
			fc_var->varlevelsup == fc_context->sublevels_up)
		{
			/* 找到匹配的变量，进行替换 */
			Node	   *fc_newnode;

			fc_newnode = fc_context->callback(fc_var, fc_context);
			/* 检测我们是否正在向查询添加子链接 */
			if (!fc_context->inserted_sublink)
				fc_context->inserted_sublink = checkExprHasSubLink(fc_newnode);
			return fc_newnode;
		}
		/* 否则正常复制变量 */
	}
	else if (IsA(fc_node, CurrentOfExpr))
	{
		CurrentOfExpr *fc_cexpr = (CurrentOfExpr *) fc_node;

		if (fc_cexpr->cvarno == fc_context->target_varno &&
			fc_context->sublevels_up == 0)
		{
			/*
			 * 如果 WHERE CURRENT OF 表达式实际上适用于一个视图，则我们在这里获得结果。总有一天，我们可能能够将表达式转换为适用于视图的底层表，但现在未实现。
			 */
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("WHERE CURRENT OF on a view is not implemented")));
		}
		/* 否则正常复制表达式 */
	}
	else if (IsA(fc_node, Query))
	{
		/* 递归进入RTE子查询或尚未规划的子链接子查询 */
		Query	   *fc_newnode;
		bool		fc_save_inserted_sublink;

		fc_context->sublevels_up++;
		fc_save_inserted_sublink = fc_context->inserted_sublink;
		fc_context->inserted_sublink = ((Query *) fc_node)->hasSubLinks;
		fc_newnode = query_tree_mutator((Query *) fc_node,
									 replace_rte_variables_mutator,
									 (void *) fc_context,
									 0);
		fc_newnode->hasSubLinks |= fc_context->inserted_sublink;
		fc_context->inserted_sublink = fc_save_inserted_sublink;
		fc_context->sublevels_up--;
		return (Node *) fc_newnode;
	}
	return expression_tree_mutator(fc_node, replace_rte_variables_mutator,
								   (void *) fc_context);
}


/*
 * map_variable_attnos() 找到表达式树中引用特定 RTE 的所有用户列 Var，并根据给定的映射数组调整它们的 varattnos（varattno n 被 attno_map[n-1] 替换）。系统列的 Var 不会被修改。
 *
 * 映射数组中的零代表一个丢弃的列，该列不应出现在表达式中。
 *
 * 如果表达式树包含目标 RTE 的整个行 Var，则 *found_whole_row 被设置为 true。此外，如果 to_rowtype 不为 InvalidOid，我们将 Var 替换为该 vartype 的 Var，并插入一个 ConvertRowtypeExpr 以映射回该表达式所期望的行类型。（因此，to_rowtype 最好是我们要更改引用的 RTE 的行类型的子行类型。）如果调用者未提供 to_rowtype，而 *found_whole_row 为 true，则应报告错误；我们在这里不这么做，因为我们不知道错误消息的确切措辞是什么最合适。调用者将了解上下文。
 *
 * 这可以使用 replace_rte_variables 和回调函数构建，但由于我们永远不需要插入子链接，replace_rte_variables 会过于复杂。
 */

typedef struct
{
	int			target_varno;	/* 要搜索的 RTE 索引 */
	int			sublevels_up;	/* （当前）嵌套深度 */
	const AttrMap *attno_map;	/* 用户 attnos 的映射数组 */
	Oid			to_rowtype;		/* 将整个行 Var 更改为此类型 */
	bool	   *found_whole_row;	/* 输出标志 */
} map_variable_attnos_context;

static Node * fc_map_variable_attnos_mutator(Node *fc_node,
							map_variable_attnos_context *fc_context)
{
	if (fc_node == NULL)
		return NULL;
	if (IsA(fc_node, Var))
	{
		Var		   *fc_var = (Var *) fc_node;

		if (fc_var->varno == fc_context->target_varno &&
			fc_var->varlevelsup == fc_context->sublevels_up)
		{
			/* 找到匹配的变量，进行替换 */
			Var		   *fc_newvar = (Var *) palloc(sizeof(Var));
			int			fc_attno = fc_var->varattno;

			*fc_newvar = *fc_var;		/* 最初复制 Var 的所有字段 */

			if (fc_attno > 0)
			{
				/* 用户定义的列，替换 attno */
				if (fc_attno > fc_context->attno_map->maplen ||
					fc_context->attno_map->attnums[fc_attno - 1] == 0)
					elog(ERROR, "unexpected varattno %d in expression to be mapped",
						 fc_attno);
				fc_newvar->varattno = fc_context->attno_map->attnums[fc_attno - 1];
				/* 如果语法参照相同的 RTE，也修复它 */
				if (fc_newvar->varnosyn == fc_context->target_varno)
					fc_newvar->varattnosyn = fc_newvar->varattno;
			}
			else if (fc_attno == 0)
			{
				/* 整行变量，警告调用者 */
				*(fc_context->found_whole_row) = true;

				/* 如果调用者希望我们转换 Var，则执行转换。 */
				if (OidIsValid(fc_context->to_rowtype) &&
					fc_context->to_rowtype != fc_var->vartype)
				{
					ConvertRowtypeExpr *fc_r;

					/* 这肯定不适用于 RECORD 变量。 */
					Assert(fc_var->vartype != RECORDOID);

					/* Var 本身被更改为请求的类型。 */
					fc_newvar->vartype = fc_context->to_rowtype;

					/*
					 * 在顶部添加一个转换节点，以转换回表达式所期望的原始类型。
					 */
					fc_r = makeNode(ConvertRowtypeExpr);
					fc_r->arg = (Expr *) fc_newvar;
					fc_r->resulttype = fc_var->vartype;
					fc_r->convertformat = COERCE_IMPLICIT_CAST;
					fc_r->location = -1;

					return (Node *) fc_r;
				}
			}
			return (Node *) fc_newvar;
		}
		/* 否则正常复制变量 */
	}
	else if (IsA(fc_node, ConvertRowtypeExpr))
	{
		ConvertRowtypeExpr *fc_r = (ConvertRowtypeExpr *) fc_node;
		Var		   *fc_var = (Var *) fc_r->arg;

		/*
		 * 如果这是在转换我们需要转换的整个行 Var，那么就直接转换 Var，而不添加额外的 ConvertRowtypeExpr。有效地说，我们将 var::parenttype::grandparenttype 简化为 var::grandparenttype。如果此函数被重复应用，这可以避免构建 CRE 的堆栈。
		 */
		if (IsA(fc_var, Var) &&
			fc_var->varno == fc_context->target_varno &&
			fc_var->varlevelsup == fc_context->sublevels_up &&
			fc_var->varattno == 0 &&
			OidIsValid(fc_context->to_rowtype) &&
			fc_context->to_rowtype != fc_var->vartype)
		{
			ConvertRowtypeExpr *fc_newnode;
			Var		   *fc_newvar = (Var *) palloc(sizeof(Var));

			/* 整行变量，警告调用者 */
			*(fc_context->found_whole_row) = true;

			*fc_newvar = *fc_var;		/* 最初复制 Var 的所有字段 */

			/* 这肯定不适用于 RECORD 变量。 */
			Assert(fc_var->vartype != RECORDOID);

			/* Var 本身被更改为请求的类型。 */
			fc_newvar->vartype = fc_context->to_rowtype;

			fc_newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
			*fc_newnode = *fc_r;		/* 最初复制 CRE 的所有字段 */
			fc_newnode->arg = (Expr *) fc_newvar;

			return (Node *) fc_newnode;
		}
		/* 否则正常处理表达式 */
	}
	else if (IsA(fc_node, Query))
	{
		/* 递归进入RTE子查询或尚未规划的子链接子查询 */
		Query	   *fc_newnode;

		fc_context->sublevels_up++;
		fc_newnode = query_tree_mutator((Query *) fc_node,
									 fc_map_variable_attnos_mutator,
									 (void *) fc_context,
									 0);
		fc_context->sublevels_up--;
		return (Node *) fc_newnode;
	}
	return expression_tree_mutator(fc_node, fc_map_variable_attnos_mutator,
								   (void *) fc_context);
}

Node * map_variable_attnos(Node *fc_node,
					int fc_target_varno, int fc_sublevels_up,
					const AttrMap *fc_attno_map,
					Oid fc_to_rowtype, bool *fc_found_whole_row)
{
	map_variable_attnos_context fc_context;

	fc_context.target_varno = fc_target_varno;
	fc_context.sublevels_up = fc_sublevels_up;
	fc_context.attno_map = fc_attno_map;
	fc_context.to_rowtype = fc_to_rowtype;
	fc_context.found_whole_row = fc_found_whole_row;

	*fc_found_whole_row = false;

	/*
	 * 必须准备从查询或裸表达式树开始；如果是查询，我们不想增加 sublevels_up。
	 */
	return query_or_expression_tree_mutator(fc_node,
											fc_map_variable_attnos_mutator,
											(void *) &fc_context,
											0);
}



/*
 * ReplaceVarsFromTargetList - 用目标列表中的项替换变量
 *
 * 匹配 target_varno 和 sublevels_up 的变量将被目标列表中
 * 相应 resno 的条目替换，如果存在的话。
 *
 * 如果没有匹配的 resno，对于这样的变量，操作取决于
 * nomatch_option:
 *	REPLACEVARS_REPORT_ERROR: 抛出错误
 *	REPLACEVARS_CHANGE_VARNO: 将变量的 varno 更改为 nomatch_varno
 *	REPLACEVARS_SUBSTITUTE_NULL: 用相同类型的 NULL 常量替换变量
 *
 * 调用者还必须提供 target_rte，描述目标
 * 关系的 RTE。这是处理引用目标的整行变量所需的。
 * 我们将这类变量展开为 RowExpr 结构。
 *
 * outer_hasSubLinks 的工作方式与 replace_rte_variables() 相同。
 */

typedef struct
{
	RangeTblEntry *target_rte;
	List	   *targetlist;
	ReplaceVarsNoMatchOption nomatch_option;
	int			nomatch_varno;
} ReplaceVarsFromTargetList_context;

static Node * fc_ReplaceVarsFromTargetList_callback(Var *fc_var,
								   replace_rte_variables_context *fc_context)
{
	ReplaceVarsFromTargetList_context *fc_rcon = (ReplaceVarsFromTargetList_context *) fc_context->callback_arg;
	TargetEntry *fc_tle;

	if (fc_var->varattno == InvalidAttrNumber)
	{
		/* 必须将整个元组引用展开为 RowExpr */
		RowExpr    *fc_rowexpr;
		List	   *fc_colnames;
		List	   *fc_fields;

		/*
		 * 如果为命名行类型的变量生成扩展（即，这是一个
		 * 普通关系 RTE），那么我们必须为被丢弃的列包含虚拟项。
		 * 如果变量是 RECORD（即，这是一个连接），那么
		 * 省略被丢弃的列。在后一种情况下，将列名附加到
		 * RowExpr，以供执行器和 ruleutils.c 使用。
		 */
		expandRTE(fc_rcon->target_rte,
				  fc_var->varno, fc_var->varlevelsup, fc_var->location,
				  (fc_var->vartype != RECORDOID),
				  &fc_colnames, &fc_fields);
		/* 调整生成的每字段变量... */
		fc_fields = (List *) replace_rte_variables_mutator((Node *) fc_fields,
														fc_context);
		fc_rowexpr = makeNode(RowExpr);
		fc_rowexpr->args = fc_fields;
		fc_rowexpr->row_typeid = fc_var->vartype;
		fc_rowexpr->row_format = COERCE_IMPLICIT_CAST;
		fc_rowexpr->colnames = (fc_var->vartype == RECORDOID) ? fc_colnames : NIL;
		fc_rowexpr->location = fc_var->location;

		return (Node *) fc_rowexpr;
	}

	/* 正常情况下引用一个目标列表元素 */
	fc_tle = get_tle_by_resno(fc_rcon->targetlist, fc_var->varattno);

	if (fc_tle == NULL || fc_tle->resjunk)
	{
		/* 未能在目标列表中找到列 */
		switch (fc_rcon->nomatch_option)
		{
			case REPLACEVARS_REPORT_ERROR:
				/* 穿透，下方抛出错误 */
				break;

			case REPLACEVARS_CHANGE_VARNO:
				fc_var = (Var *) copyObject(fc_var);
				fc_var->varno = fc_rcon->nomatch_varno;
				/* 我们不动语法参考 */
				return (Node *) fc_var;

			case REPLACEVARS_SUBSTITUTE_NULL:
				{
					/*
					 * 如果 Var 是域类型，我们必须添加一个 CoerceToDomain
					 * 节点，以防存在 NOT NULL 域约束。
					 */
					int16		fc_vartyplen;
					bool		fc_vartypbyval;

					get_typlenbyval(fc_var->vartype, &fc_vartyplen, &fc_vartypbyval);
					return coerce_null_to_domain(fc_var->vartype,
												 fc_var->vartypmod,
												 fc_var->varcollid,
												 fc_vartyplen,
												 fc_vartypbyval);
				}
		}
		elog(ERROR, "could not find replacement targetlist entry for attno %d",
			 fc_var->varattno);
		return NULL;			/* 保持编译器安静 */
	}
	else
	{
		/* 复制tlist项目以返回 */
		Expr	   *fc_newnode = copyObject(fc_tle->expr);

		/* 如果tlist项目来自更高的查询，必须调整varlevelsup */
		if (fc_var->varlevelsup > 0)
			IncrementVarSublevelsUp((Node *) fc_newnode, fc_var->varlevelsup, 0);

		/*
		 * 检查 tlist 项是否包含一个 PARAM_MULTIEXPR Param，
		 * 如果是，则抛出错误。 这种情况只能在扩展
		 * ON UPDATE 规则的 NEW 变量时发生，而在原始 UPDATE 命令中的
		 * 被引用的 tlist 项是多个赋值的一部分。 似乎没有实际方法
		 * 可以处理这种情况，而不对多个赋值的子选择进行多次评估，
		 * 这将导致语义上的奇异，规则的用户可能更希望
		 * 不去处理。因此将其视为未实现的功能。
		 */
		if (fc_contains_multiexpr_param((Node *) fc_newnode, NULL))
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));

		return (Node *) fc_newnode;
	}
}

Node * ReplaceVarsFromTargetList(Node *fc_node,
						  int fc_target_varno, int fc_sublevels_up,
						  RangeTblEntry *fc_target_rte,
						  List *fc_targetlist,
						  ReplaceVarsNoMatchOption fc_nomatch_option,
						  int fc_nomatch_varno,
						  bool *fc_outer_hasSubLinks)
{
	ReplaceVarsFromTargetList_context fc_context;

	fc_context.target_rte = fc_target_rte;
	fc_context.targetlist = fc_targetlist;
	fc_context.nomatch_option = fc_nomatch_option;
	fc_context.nomatch_varno = fc_nomatch_varno;

	return replace_rte_variables(fc_node, fc_target_varno, fc_sublevels_up,
								 fc_ReplaceVarsFromTargetList_callback,
								 (void *) &fc_context,
								 fc_outer_hasSubLinks);
}
